package game;


import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Timer;
import org.newdawn.slick.SlickException;



/**
 * Die Spielmechanik des Pong Spiels. Verwaltet den Gamestate, verbindet das GUI mit der Arena und dem Startmenü.
 * 
 * @author mariuswi
 * 
 */
public class GameControl {
    
  
    
    //Attribute
    private int gamestate; //Die verschiedenen Zustände in denen sich das Spiel befinden kann
    private GameGui gamegui; //Referenz zur GUI
    private Arena arena; //Referenz zum Spielfeld
    private Drawable[] drawables; //Liste mit den zu rendernden Objekten
    private int maxPoints; //maximale Punktzahl eines Spiels

    
    
    //Konstruktor
    GameControl(GameGui gamegui){
        this.gamestate = 10; //Gamestate 10: Hauptmenü
        this.gamegui = gamegui;
        
    }
    //Methoden
    
    GameControl(){
        //Not Implemented yet
    }
    
    /**
     * Setzt Gamestate.
     * 
     * 1 = 
     * 2 = Laufendes Spiel mit zwei Spielern
     * 8 = Spiel pausiert
     * 10 = Startmenü
     * 
     * @param gamestate 
     */
    
    public void setGamestate(int gamestate) {
        this.gamestate = gamestate;
    }
    
     /**
     * Gibt den momentanen Zustand des Spiels zurück.
     * Liste der Zustände siehe this.setGamestate
     * @return gamestate 
     */
    public int getGamestate(){
        return this.gamestate;
    }
    
    /**
     * Pause Funktion.
     * Pausiert die Spielmechanik für x ms.
     * 
     * Bei 0 wird unbegrenzt pausiert.
     * 
     * @param x Pause in Millisekunden
     */
    private void pause(int x){
        this.gamestate = 8;
        if(x != 0 ){
        Timer t1 = new Timer(x,null);
        t1.setRepeats(false);
        final GameControl c = this;
        
        ActionListener a = new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                if(c.getGamestate()==8)
                    c.setGamestate(2);
            }
        };
        t1.addActionListener(a);
        t1.start();
        }
        
    }
    /**
     * Initialisiert ein lokales 2-Spieler Spiel.
     * 
     * @throws SlickException 
     */
    public void startOfflineGame(int numberOfPlayers) throws SlickException{

        //Spieleinstellungen einstellen
        this.arena = new Arena(20000,20000); //Arenagröße ( Modellgröße) x und y werden übergeben
        this.gamegui.setArenaSize(20000, 20000); //Arenagröße der Gui mitteilen
        
        switch(numberOfPlayers){
            case 2: this.drawables = this.arena.initTwoPlayerGame();break;
            case 3: this.drawables = this.arena.initThreePlayerGame();break;
            default: System.out.println("Ungültige Anzahl an Spieler !");break;
        }
        this.maxPoints = 10; //maximale Punktzahl = 10

        
        this.gamestate = 2; //Gamestate 2: lokales 2-Spieler Spiel... ab hier wird das Spiel gerendert und die Update Methoden aufgerufen
    }
    
    /**
     * Gibt eine Liste mit den zu rendernden Objekten zurück. Jedes dieser Objekte besitzt eine eigene draw() Methode, die aufgerufen werden kann
     * 
     * @return Liste mit zu rendernden Objekten
     */
    public Drawable[] getDrawables(){
       return this.drawables;   
    }
    /**
     * Um einen Spielerbedingten Input auszuführen wird diese Methode aufgerufen
     * 
     * @param Player
     * 'l':left, racket 0
     * 'r':right, racket 1
     * 'b':bottom, racket 2
     * 't':top, racket 3
     *
     * @param command 
     * 'u': move racket up/right
     * 'd': move racket down/left
     */
    public void incomingInput(CInput input) throws SlickException{
        
        switch(input.getCommand()){
            case CInput.EXIT: this.exit(); break;
            case CInput.TWOPLAYER: this.startOfflineGame(2); break;
            case CInput.THREEPLAYER: this.startOfflineGame(3); break;
            case CInput.PAUSE: if(this.gamestate == 8){this.gamestate = 2;}else{this.pause(0);}; break; //Reset Funktion wurde durch Pause ersetzt
            case CInput.MENU: arena.exit(); this.gamestate = 10; break;
            default: arena.moveRacket(input);
        }
    }
    
    /**
     * Initialisiert das Netzwerk
     * 
     * @deprecated Netzwerkfunktion wurde aus den Anforderungen genommen.
     */
    public void initializeNetwork(){
        
    }
    
    /**
     * Faengt Inputs vom Netzwerk auf. Wertet Input aus und setzt alle enthaltenen Positionen.
     * 
     * @deprecated Netzwerkfunktion wurde aus den Anforderungen genommen.
     * @param input
     */
    public void incomingRemoteInput (String input) {
        
    }
    
    /**
     * Konvertiert Positionen aller Objekte im Array Networkable.
     * 
     * @return Gibt Positionen in Form xPos1;yPos1;xPos2;yPos2;... zurueck
     * @deprecated Netzwerkfunktion wurde aus den Anforderungen genommen.
     */
    public String getNetworkablePositions () {
        return new String();
    }
    
    /**
     * Updatet das Spiel und das Spielfeld.
     * Zieht Spielern Leben ab und prüft, ob jemand das Spiel gewonnen hat.
     * 
     * 1. Bewege den Ball
     * 2. Ist der Ball draußen ? -> neustart oder beende das Spiel
     */
    public void update() throws ArrayIndexOutOfBoundsException {
        
        // Pong bewegen
        boolean hadCollission = this.arena.movePong();
        
        //Test, ob der Pong außerhalb des Spielfeldes ist
        if(!hadCollission){
        
            if(this.arena.isPongOut()){
                //Zieht dem entsprechenden Spieler ein Leben ab.
                char id = this.arena.pongOutAtSide();
                int nr;
                
                switch (id) {
                    case 'l': nr = 0; break;
                    case 'r': nr = 1; break;
                    case 'b': nr = 2; break;
                    case 't': nr = 3; break;
                    default: nr = 4; break;
                }
                
                try {
                    arena.getPlayers()[nr].dieOnce();
                }
                catch (ArrayIndexOutOfBoundsException e) {
                    e.printStackTrace();
                }

                Playerlifes[] players = arena.getPlayers();
                
                // Spiel abbrechen, wenn jemand gewonnen hat.
                for(int i = 0; i<players.length; i++){
                    if(players[i].getLifes()<= 0){
                    this.setGamestate(8);
                    //Spielende
                    return;
                    }   
                }
                
                //Ball wird zurückgesetzt
                this.arena.resetPong();
                this.pause(1000);
            }
        }   
    }
    
    /**
     * Beendet das Spiel
     */
    public void exit(){
        
        //Letzter Schritt vor dem Beenden
        gamegui.exit();
    }
}
